package libraries;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;

import transgui.TransPartLibraryList;

public class LibraryContainer {

	
	LinkedList<TransPartLibrary> libraries;
	
	public LibraryContainer() {
		this.libraries = new LinkedList<TransPartLibrary>();
	}
	
	/**
	 * creates and returns a library container with a single predefined library
	 * @return
	 */
	public static LibraryContainer testLibraryContainer() {
		LibraryContainer libCon = new LibraryContainer();
		libCon.addLibrary(TransPartLibrary.testLibrary());
		
		return libCon;
	}
	
	/**
	 * creates and returns an empty library
	 * @param name the name of the library
	 * @return
	 */
	public String addLibrary (String name) {
		return addLibrary(newLib(name));
	}
	
	/**
	 * adds a library object to the library list
	 * @param lib the library to be added
	 * @return returns "" if the library is accepted or an error message
	 */
	
	public String addLibrary (TransPartLibrary lib) {
		String check = checkLibraryConsistency(lib);
		
		if (check.equals("")) {
			libraries.add(lib);
			return "";
		} else {
			return check;
		}
	}
	
	/**
	 * checks a library for consistency. A library is consistent if it doesn't 
	 * share a name with any other library and its parts either don't share matching
	 * or match and return the same modelica path and other traits in translation
	 * @param lib the library to be compared
	 * @return
	 */
	public String checkLibraryConsistency (TransPartLibrary lib) {
		for (int i = 0; i< libraries.size(); i++) {
			if (lib.name == libraries.get(i).name && lib != libraries.get(i)) {
				return "A library with name "+ lib.name + " already exists";
			}
		}
		for (int i = 0; i < lib.getSize(); i++) {
			String error = checkPartConsistency(lib.get(i), lib);
			if (error.equals("") == false){
				return error;
			}
		}
		return "";
	}

	/**
	 * checks a part for consistency. A part is consistent if it shares matching only
	 * with parts that come to the same translation result and doesn't share matching
	 * at all with parts in the same library. 
	 * @param part
	 * @param lib
	 * @return
	 */
	public String checkPartConsistency (TransPart part, TransPartLibrary lib) {
		for (int l = 0; l < libraries.size(); l++) {
			for (int p = 0; p < libraries.get(l).getSize(); p++){
				if (part.badMatches(libraries.get(l).get(p))) {
					String error = "Part " + part.toString() + " shares matching with " + libraries.get(l).get(p).toString() + " from Library " + libraries.get(l).name + ", but has different values.";
					return error;
				}
				if (libraries.get(l).getName().equals(lib.getName()) && part.matches(libraries.get(l).get(p))) {
					String error = "Part already exists in library " + lib;
					return error;
				}
			}
		}
		return "";
	}
	
	/**
	 * searches for a TransPart in all libraries for translation purposes 
	 * @param dev EAGLE device
	 * @param pac EAGLE package
	 * @param lib EAGLE library
	 * @return the TransPart that matches the given parameters
	 */
	public TransPart find(String dev, String pac, String lib) {
		for (TransPartLibrary l: libraries) {
			TransPart result = l.find(dev, pac, lib);
			if (result != null) {
				return result;
			}
		}
		return null;
	}
	
	/** 
	 * reads a library file (.edl) and creates a library from it
	 * @param libFile
	 * @return returns "" if the library was successfully added, otherwise notes the cause of error
	 * @throws IOException
	 */
	public String readLibraryFile(File libFile) throws IOException {
		BufferedReader in = null;
		LinkedList<String> text = new LinkedList<String>();
		
		try {
			in = new BufferedReader(new FileReader(libFile));
			String s;
            while ((s = in.readLine()) != null) {
            	text.add(s);
            }
            return interpretLibFile(text);
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	/**
	 * creates a library from the lines of a .edl file
	 * @param text the strings of an .edl file
	 * @return returns "" if the library was successfully added, otherwise notes the cause of error
	 * @throws IOException
	 */
	private String interpretLibFile(LinkedList<String> text) throws IOException {
		if(!text.getFirst().equals("EAGLEModelicaConversionLibrary")) {
			throw (new IOException("File is not a valid library"));
		}
		String name = text.get(1);
		TransPartLibrary lib = newLib(name);
		//possibly use a higher starting index if overhead is added to library file!
		for (int i = 2; i < (text.size()-1); i++) {
			//attention: i is incremented within the loop for a second line read!
			String partS = text.get(i);
			String[] partA = partS.split("\\|");
			i++;
			String connS = text.get(i);
			String[] connA = connS.split("\\|");
			LinkedList<String> connKeys = new LinkedList<String>();
			LinkedList<String> connVals = new LinkedList<String>();
			for (String j: connA) {
				String[] keyval = j.split(" ");
				connKeys.add(keyval[0]);
				connVals.add(keyval[1]);
			}
			TransConn conn = new TransConn(connKeys, connVals);
			lib.add(new TransPart(partA[0], partA[1], partA[2], partA[3], conn, partA[4], Integer.parseInt(partA[5]), partA[6]));
		}
		return addLibrary(lib);
	}
	
	/**
	 * writes a library to file
	 * @param file the file name for the export
	 * @param name the name of the library
	 * @throws IOException
	 */
	public void writeLibraryFile(File file, String name) throws IOException {
		TransPartLibrary l = getLibrary(name);
		if (l != null) {
			l.writeLibraryFile(file);
		}
	}
	
	/**
	 * searches for a library
	 * @param name the name of the library
	 * @return the library with the given name
	 */
	public TransPartLibrary getLibrary(String name) {
		for (TransPartLibrary l: libraries) {
			if (l.name == name) {
				return l;
			}
		}
		return null;
	}
	
	public LinkedList<TransPartLibrary> getLibraries() {
		return libraries;
	}

	protected TransPartLibrary newLib(String name) {
		return new TransPartLibrary(name);
	}

	public void deleteLibrary(TransPartLibrary lib) {
		libraries.remove(lib);
	}

	/**
	 * adds a TransPart to a library if it is consistent
	 * @param lib the library where the part is to be added
	 * @param part the part to be added
	 * @return "" if successful, otherwise a description of the inconsistency
	 */
	public String addPart(TransPartLibraryList lib, TransPart part) {
		String result = checkPartConsistency(part, lib);
		if(result.equals("")) {
			lib.add(part);
		}
		return result;
	}
}
